package com.changgou.oauth.service.impl;

import com.changgou.oauth.service.UserLoginService;
import com.changgou.oauth.util.AuthToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Base64;
import java.util.Map;

/**
 * @Author: wzw
 * @Date: 2020/12/22 16:31
 * @version: 1.8
 */
@Service
public class UserLoginServiceImpl implements UserLoginService {

    //注入负载均衡客户端:获取动态端口
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    //注入RestTemplate模板
    @Autowired
    private RestTemplate restTemplate;

    /**
     * @author wzw
     * @Description 用户登录认证:调用Oauth2.0提供的接口(固定路径URL),生成令牌
     * @Date 17:11 2019/10/26
     * @param username      用户名
     * @param password      密码
     * @param clientId      客户端id
     * @param clientSecret  客户端秘钥
     * @param grant_type    密码授权方式
     * @return java.util.Map<java.lang.String,java.lang.String>
     **/
    @Override
    public AuthToken login(String username, String password, String clientId, String clientSecret, String grant_type) {
        try {
            // 1.指定授权的url地址(Oauth接口地址)
            // 1.1 获取配置文件中的服务实例(对象)
            ServiceInstance serviceInstance = loadBalancerClient.choose("user-auth");
            // 1.2 拿到uri:地址+端口(http://localhost:9001)
            String uri = serviceInstance.getUri().toString();
            // 1.3 拼接生成令牌的固定路径:/oauth/token
            String url = uri + "/oauth/token";

            // 2.封装请求数据
            // 2.1封装请求头
            // 2.1.1对客户端信息进行Base64编码,直接toString转字符了
            String clientEncode = Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes());
            // 2.1.3 new LinkedMultiValueMap对象封装请求头
            LinkedMultiValueMap headers = new LinkedMultiValueMap<>();
            // 2.1.4 将数据以key和value形式添加到LinkedMultiValueMap对象中(固定值,固定值+Base64编码后的信息)
            // 注意:Basic后面要多一个空格(格式要求)
            headers.add("Authorization","Basic "+clientEncode);
            // 2.2封装请求体
            LinkedMultiValueMap body = new LinkedMultiValueMap<>();
            // 2.2.1 密码授权方式:password
            body.add("grant_type",grant_type);
            // 2.2.2 登录的用户账号
            body.add("username",username);
            // 2.2.3 登录的用户密码
            body.add("password",password);

            // 3. new HttpEntity封装对象(请求头,请求体)
            //有坑:body虽然是泛型,但只能要LinkedMultiValueMap封装数据
            HttpEntity requestEntity = new HttpEntity<>(body,headers);

            // 4.发送请求:(url路径,http的post请求方式,封装请求头+请求体的对象,响应的实体对象)
            ResponseEntity<Map> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);

            // 5.响应结果处理
            // 5.1获取生成的令牌
            Map<String,Object> map = responseEntity.getBody();

            // 5.2处理结果集
            //创建pojo封装数据
            AuthToken authToken = new AuthToken();
            //封装令牌
            authToken.setAccessToken(map.get("access_token").toString());
            //封装刷新令牌
            authToken.setRefreshToken(map.get("token_type").toString());
            //封装唯一标识符
            authToken.setJti(map.get("jti").toString());

            //返回参数
            return authToken;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
